package big_cache

import (
	"context"
	"github.com/allegro/bigcache/v3"
	"github.com/goccy/go-json"
	"go.uber.org/zap"
	log "gobase/logger"
	"sync"
)

type BigCache struct {
	*bigcache.BigCache
	sync.RWMutex
}

// InitBigCache 创建一个BigCache
//
//	config := bigcache.Config{
//		Shards:             1024,            // 存储的条目数量，值必须是2的幂
//		LifeWindow:         5 * time.Minute, // 超时后条目被处理
//		CleanWindow:        2 * time.Minute, // 处理超时条目的时间范围
//		MaxEntriesInWindow: 0,               // 在 Life Window 中的最大数量，
//		MaxEntrySize:       0,               // 条目最大尺寸，以字节为单位
//		HardMaxCacheSize:   0,               // 设置缓存最大值，以MB为单位，超过了不在分配内存。0表示无限制分配
//		OnRemove:           nil,             // 当最旧的条目因为过期或没有空间留给新条目而被删除时，触发回调。默认值是nil，这意味着没有回调，它可以防止解开最旧的条目
//		OnRemoveWithReason: nil, 			 // 在缓存过期或者被删除时,可设置回调函数，参数是(key、val,reason)默认是nil不设置
//		Verbose:            false,           // 打印关于额外内存分配的信息
//	}
func InitBigCache(config bigcache.Config) *BigCache {

	var err error
	c := new(BigCache)

	c.BigCache, err = bigcache.New(context.Background(), config)
	if err != nil {
		log.Error("Big Cache err : ", zap.Error(err))
		return nil
	} else {
		return c
	}
	// cache.Stats()
}

func (bc *BigCache) SetAny(key string, obj interface{}) error {
	b, err := AnyToByte(obj)
	if err != nil {
		log.Error(err.Error())
		return err
	}
	return bc.Set(key, b)
}

func (bc *BigCache) GetAny(key string, obj interface{}) error {
	b, err := bc.Get(key)
	if err != nil {
		if err == bigcache.ErrEntryNotFound {
			log.Warn("key cache not found", zap.String("key", key), zap.Error(err))
			return nil
		}
		log.Error(err.Error())
		return err
	}
	return ByteToAny(b, obj)
}

func (bc *BigCache) GetSet(k string, v interface{}) error {
	data, err := bc.Get(k)
	if err != nil {
		if err == bigcache.ErrEntryNotFound {
			return bc.SetAny(k, v)
		}
		return err
	}
	return ByteToAny(data, v)
}

func AnyToByte(obj interface{}) ([]byte, error) {
	return json.Marshal(obj)
}

func ByteToAny(data []byte, a interface{}) error {
	return json.Unmarshal(data, a)
}
